﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Evpo.ContactData.Common;

namespace Evpo.ContactData.Data
{
    public abstract class DictionaryItemAdapter
    {
        public DictionaryItemAdapter(Connection conn)
        {
            _conn = conn;
        }

        #region Const
        #endregion
        
        #region Fields
        protected readonly Connection _conn;
        private static Dictionary<string, int> _idForUnspecified = new Dictionary<string,int>();
        private static Dictionary<string, string> _displayNames = new Dictionary<string, string>();
        #endregion

        #region Properties

        protected abstract string DictionaryName
        {
            get;
        }

        protected virtual string GetItemSProc
        {
            get
            {
                throw new NotImplementedException();
            }
        }
        #endregion

        #region Methods
        private void PopulateStaticDictionaries()
        {
            if (_idForUnspecified.Count > 0)
                return;

            using (var procReader = new ProcedureOutputReader(_conn, SProcs.DictionaryIDForUnspecified))
            {
                SqlDataReader reader = procReader.CreateReader();
                while (reader.Read())
                {
                    string name = procReader.GetString("DictionaryName");
                    _idForUnspecified.Add(
                        name,
                        procReader.GetID("ID"));

                    _displayNames.Add(
                        name,
                        procReader.GetString("DisplayName"));
                }
            }
        }

        public int GetIDForUnspecified()
        {
            PopulateStaticDictionaries();
            return _idForUnspecified[DictionaryName];
        }

        public string GetDisplayName()
        {
            PopulateStaticDictionaries();
            return _displayNames[DictionaryName];
        }

        public virtual string GetName(int id)
        {
            return GetDictionaryItem<DictionaryItem>(id).Name;
        }

        internal virtual void SetAdditionalParams(SqlDataReader sqlDataReader, DictionaryItem item)
        {
        }

        internal T GetDictionaryItem<T>(int id) where T : DictionaryItem, new()
        {
            T retVal = null;
            List<SqlParameter> parameters = new List<SqlParameter>()
            {
                new SqlParameter("@" + Fields.ID, id),
            };
            using (var procReader =
                new ProcedureOutputReader(_conn, GetItemSProc, parameters))
            {
                SqlDataReader reader = procReader.CreateReader();
                if (!reader.Read())
                    throw new ParamAppException("ID '{0}' is not found", id);
                retVal = new T()
                {
                    ID = reader.GetInt32(reader.GetOrdinal(Fields.ID)),
                    Name = reader.GetString(reader.GetOrdinal(Fields.Name)),
                };
                SetAdditionalParams(reader, retVal);
            }
            return retVal;
        }

        internal List<T> GetDictionaryItems<T>(string sproc) where T : DictionaryItem, new()
        {
            List<T> retVal = new List<T>();
            using (var procReader =
                new ProcedureOutputReader(_conn, sproc))
            {
                SqlDataReader reader = procReader.CreateReader();
                while (reader.Read())
                {
                    T item = new T()
                    {
                        ID = reader.GetInt32(reader.GetOrdinal(Fields.ID)),
                        Name = reader.GetString(reader.GetOrdinal(Fields.Name)),
                    };
                    retVal.Add(item);
                    SetAdditionalParams(reader, item);
                }
            }
            if (retVal.Count == 0)
                throw new ApplicationException("No items found in the table");
            return retVal;
        }

        internal static void FillParametersToSave(DictionaryItem item, List<SqlParameter> paramList)
        {
            if (paramList == null)
                throw new ArgumentNullException("paramList");

            paramList.Add(new SqlParameter("@" + Fields.Name, item.Name));
        }

        internal static void FillFieldsFromReader(DictionaryItem item, ProcedureOutputReader procReader)
        {
            item.ID = procReader.GetID(Fields.ID);
            item.Name = procReader.GetString(Fields.Name);
        }

        #endregion Methods

        #region Private Classes
        private class Fields
        {
            internal const string ID = "ID";
            internal const string Name = "Name";
        }
        #endregion
    }
}
